package com.derbysoft.ota.application.translator.rs;

import java.util.List;
import java.util.Map.Entry;

import javax.annotation.Nullable;

import com.derbysoft.ota.interfaces.protocol._2009a.OTAHotelAvailRS.Criteria;
import org.apache.commons.collections.CollectionUtils;

import com.derbysoft.modules.eip.translator.Translator;
import com.derbysoft.ota.interfaces.protocol._2009a.DateTimeSpanType;
import com.derbysoft.ota.interfaces.protocol._2009a.OTAHotelAvailRS;
import com.derbysoft.ota.interfaces.protocol._2009a.AvailRequestSegmentsType.AvailRequestSegment;
import com.derbysoft.ota.interfaces.protocol._2009a.OTAHotelAvailRS.RoomStays;
import com.derbysoft.ota.interfaces.protocol._2009a.OTAHotelAvailRS.RoomStays.RoomStay;
import com.derbysoft.ota.interfaces.protocol._2009a.RoomStayType.RatePlans;
import com.derbysoft.ota.interfaces.protocol._2009a.RoomStayType.RoomRates;
import com.derbysoft.ota.interfaces.protocol._2009a.RoomStayType.RoomTypes;
import com.derbysoft.ota.interfaces.protocol._2009a.RoomStayType.RoomRates.RoomRate;
import com.derbysoft.remote.dswitch.hotel.dto.AvailRoomStayDTO;
import com.derbysoft.remote.dswitch.hotel.dto.HotelMultiProviderAvailRS;
import com.derbysoft.remote.dswitch.hotel.dto.ProviderAvailRoomStayDTO;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.googlecode.functionalcollections.FunctionalIterable;
import com.googlecode.functionalcollections.FunctionalIterables;
import com.googlecode.functionalcollections.Injector;

public class HotelAvailRSTranslator implements Translator<HotelAvailRSSource, OTAHotelAvailRS> {

	private Translator<Entry<AvailRoomStayDTO, DateTimeSpanType>, RoomRate> availRoomRateTranslator;
	private Translator<AvailRequestSegment, Criteria> hotelAvailRSCriteriaTranslator;

	@Inject
	public HotelAvailRSTranslator(Translator<Entry<AvailRoomStayDTO, DateTimeSpanType>, RoomRate> availRoomRateTranslator,
							   Translator<AvailRequestSegment, Criteria> hotelAvailRSCriteriaTranslator) {
		this.availRoomRateTranslator = availRoomRateTranslator;
		this.hotelAvailRSCriteriaTranslator = hotelAvailRSCriteriaTranslator;
	}

	public OTAHotelAvailRS translate(HotelAvailRSSource source) {
		OTAHotelAvailRS otaHotelAvailRS = source.getOtaRS();
		HotelMultiProviderAvailRS switchRS = source.getSwitchRS();

		AvailRequestSegment segment =
        	FunctionalIterables.make(source.getOtaRQ().getAvailRequestSegments().getAvailRequestSegment())
        					   .messagedIterator("Please provide at least 1 avail request segment.").next();

		otaHotelAvailRS.setRoomStays(roomStays(switchRS.getProviderAvailRoomStays(), segment.getStayDateRange()));
		otaHotelAvailRS.setCriteria(hotelAvailRSCriteriaTranslator.translate(segment));
		return otaHotelAvailRS;
	}


	private RoomStays roomStays(List<ProviderAvailRoomStayDTO> providerAvailRoomStays, final DateTimeSpanType dateTimeSpanType) {
        if (CollectionUtils.isEmpty(providerAvailRoomStays)) {
            return null;
        }
        RoomStays roomStays = new RoomStays();
        roomStays.getRoomStay().addAll(FunctionalIterables.make(providerAvailRoomStays)
                .inject(
                    FunctionalIterables.<RoomStay>create(),
                    new Injector<FunctionalIterable<RoomStay>, ProviderAvailRoomStayDTO>() {
                        public FunctionalIterable<RoomStay> apply(
                            FunctionalIterable<RoomStay> memo,
                            @Nullable ProviderAvailRoomStayDTO input) {

                            return memo.concat(roomStay(input, dateTimeSpanType));
                        }
                    }
                ).toCollection());
        return roomStays;
    }

	private Iterable<RoomStay> roomStay(final ProviderAvailRoomStayDTO providerRoomStay, final DateTimeSpanType dateTimeSpanType) {
		return FunctionalIterables.make(providerRoomStay.getHotelAvailRoomStay().getRoomStays()).map(
				new Function<AvailRoomStayDTO, RoomStay>() {
					public RoomStay apply(AvailRoomStayDTO from) {
						RoomStay roomStay = new RoomStay();
						roomStay.setInfoSource(providerRoomStay.getProvider().getId());
						roomStay.setRatePlans(ratePlans(from));
						roomStay.setRoomRates(roomRates(from, dateTimeSpanType));
						roomStay.setRoomTypes(roomTypes(from));
						roomStay.setTimeSpan((DateTimeSpanType) dateTimeSpanType.clone());
						if(CollectionUtils.isNotEmpty(from.getRatePlan().getAvailGuarantees())) {
							roomStay.getGuarantee().addAll(new GuaranteeTypeRSTranslator().translate(from.getRatePlan().getAvailGuarantees()));
						}
						return roomStay;
					}
				}
		);
	}

	private RoomRates roomRates(AvailRoomStayDTO from, DateTimeSpanType dateTimeSpanType) {
		RoomRates roomRates = new RoomRates();
		roomRates.getRoomRate().add(availRoomRateTranslator.translate(Maps.immutableEntry(from, dateTimeSpanType)));
		return roomRates;
	}

	private RatePlans ratePlans(AvailRoomStayDTO from) {
		RatePlans ratePlans = new RatePlans();
		ratePlans.getRatePlan().add(new RatePlanTranslator().translate(from));
		return ratePlans;
	}


	private RoomTypes roomTypes(AvailRoomStayDTO from) {
		RoomTypes roomTypes = new RoomTypes();
		roomTypes.getRoomType().add(new RoomTypeTranslator().translate(from.getRoomType()));
		return roomTypes;
	}
}
